#ifndef FILE_APPENDER_H
#define FILE_APPENDER_H
#include "log_appender.h"
#include "boost/filesystem.hpp" 
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/fstream.hpp"
#include "utils/time_utils.hpp"


namespace fs = boost::filesystem;   
namespace vpm
{
	namespace log 
	{
		namespace detail
		{
			class FileAppender : public LogAppender
			{
			public:
                FileAppender(boost::shared_ptr<FileAppenderConfig>  cfg)
                    :LogAppender(cfg,LogConfig::LOGGER_FILE)
                {
                    m_fileSize = 0; 
					m_filePath    = cfg->file_path();
                    printf("Create log file path :%s\n",m_filePath.c_str());
					m_fileName    = cfg->file_name();
                    m_filePostfix = cfg->file_postfix(); 
                    m_fileAppenderConfig = cfg; 
				}

				~FileAppender()
				{
					if (m_fileStream && m_fileStream.is_open())
					{
						m_fileStream.close();
					}
				}

				virtual int open()
                {		
                    //printf("Create single log file \n");
                    rename_last_log_file(m_fileName);
                    this->create_log_file(m_fileName);
                    return 0; 
                }

				virtual void close()
				{
					if (m_fileStream && m_fileStream.is_open())
					{
						m_fileStream.close();
					}
				}

                std::string log_file_time_stamp() const 
                {
                    char timeBuf[512];
                    const char * timeStamp = "_%m_%d_%H%M%S";
                    time_t curTime = time(0);
                    size_t len = ::strftime(timeBuf, sizeof(timeBuf), timeStamp, localtime(&curTime));
                    timeBuf[len] =0;
                    return std::string (timeBuf);
                }

				virtual void do_append(LogMessageBlock *pLogMsg)
				{
                    if (!m_fileStream)
                    {
                        return ; 
                    }

                    if (m_fileAppenderConfig->single_file())
                    {
                        std::copy(pLogMsg->begin(),pLogMsg->end(), std::ostream_iterator<char>(m_fileStream));		
                        try 
                        {
                            m_fileStream.flush();
                        }
                        catch (...)
                        {
                            create_log_file(m_fileName);
                            return ;
                        }
                    }
                    else 
                    {
                        m_fileSize += pLogMsg->length();
                        std::copy(pLogMsg->begin(),pLogMsg->end(), std::ostream_iterator<char>(m_fileStream));		
                        try 
                        {
                            m_fileStream.flush();
                        }
                        catch (...)
                        {
                            create_log_file(m_fileName);
                            m_fileSize = 0; 
                            return ;
                        }

                        if (m_fileSize >= m_fileAppenderConfig->file_size() )
                        {
                            m_fileStream.close();
                            //move the old file to another name
                            fs::path filePath = fs::path(m_filePath,fs::native);
                            fs::path oldFile = filePath/(m_fileName + m_filePostfix); 
                            fs::path newFile = filePath/(m_fileName+log_file_time_stamp()+ m_filePostfix);

                            printf("oldfile :%s\n",((const std::string&)oldFile).c_str());
                            printf("newFile :%s\n",((const std::string&)newFile).c_str());
                            if (fs::exists(oldFile) )
                            {
                                if (!fs::exists(newFile))
                                {
                                    printf("rename file success\n");
                                    fs::rename(oldFile,newFile);
                                }
                                else 
                                {
                                    //just drop that file 
                                }
                            }

                            //create the single file again
                            m_fileSize = 0; 
                            create_log_file(m_fileName);
                        }
                    }
				}
                void rename_last_log_file(const std::string & fileName)
                {
                    fs::path filePath = fs::path(m_filePath,fs::native);
                    fs::path oldFile= filePath / (fileName+ m_filePostfix);
                    if (fs::exists(oldFile))
                    {
                        fs::path newFile = filePath/(m_fileName+log_file_time_stamp()+ m_filePostfix);
                        if (fs::exists(oldFile) )
                        {
                            if (!fs::exists(newFile))
                            {
                                printf("rename last log file success\n");
                                fs::rename(oldFile,newFile);
                            }
                            else 
                            {
                                //just drop that file 
                            }
                        }
                    }
                }

                int create_log_file(const std::string & fileName)
                {
//                    char exePath[512];
//                    getcwd(exePath,sizeof(exePath));
//                    std::cout <<"Current exe path is "<<exePath<<std::endl; 

                    printf("create log file %s\n",fileName.c_str());
                    fs::path filePath = fs::path(m_filePath,fs::native);
                    //printf("Create log file name:%s\n",fileName.c_str());

                    if (!fs::exists(filePath))
                    {
                        if (!fs::create_directory(filePath))
                        {
                            std::cerr<<"Create log directory failed\n";
                            return -1; 
                        }
                    }

                    filePath = filePath / (fileName+ m_filePostfix);
                    printf("try to open log file %s\n",((const std::string&)filePath).c_str());
                    m_fileStream.open(filePath,std::ios_base::out);
                    
                    if (!m_fileStream)
                    {
                        return -1; 
                    }
                    return 0; 
                }

			private:
                int m_fileSize ;
                fs::ofstream m_fileStream; 
                std::string m_filePath; 
                std::string m_fileName; 
                std::string m_filePostfix;

                std::string m_currentFileName; 
                boost::shared_ptr<FileAppenderConfig> m_fileAppenderConfig; 
            };
        }
	}
}

#endif // 
  
